import { Solar, Lunar, EightChar } from 'lunar-typescript'

// ==================== 类型定义 ====================

export interface 生辰 {
  类型: "公历" | "农历",
  年: number,
  月: number,
  日: number,
  时: number,
  分?: number,
  秒?: number
}

export type 阴阳 = "阳" | "阴" | "";
export type 五行 = "木" | "火" | "土" | "金" | "水" | "";

export interface 柱 {
  天干: string;
  地支: string;
  纳音: string;
  藏干: string[];
  天干十神: string;
  地支十神: string[];
  地势: string;
  天干阴阳: 阴阳;
  天干五行: 五行;
  地支阴阳: 阴阳;
  地支五行: 五行;
}

// ==================== 常量定义 ====================

/** 天干地支阴阳映射表 */
const 阴阳映射表: Readonly<Record<string, 阴阳>> = {
  // 天干
  '甲': '阳', '乙': '阴',
  '丙': '阳', '丁': '阴',
  '戊': '阳', '己': '阴',
  '庚': '阳', '辛': '阴',
  '壬': '阳', '癸': '阴',
  // 地支
  '子': '阳', '丑': '阴',
  '寅': '阳', '卯': '阴',
  '辰': '阳', '巳': '阴',
  '午': '阳', '未': '阴',
  '申': '阳', '酉': '阴',
  '戌': '阳', '亥': '阴'
} as const;

/** 天干地支五行映射表 */
const 五行映射表: Readonly<Record<string, 五行>> = {
  // 天干
  '甲': '木', '乙': '木',
  '丙': '火', '丁': '火',
  '戊': '土', '己': '土',
  '庚': '金', '辛': '金',
  '壬': '水', '癸': '水',
  // 地支
  '子': '水', '丑': '土',
  '寅': '木', '卯': '木',
  '辰': '土', '巳': '火',
  '午': '火', '未': '土',
  '申': '金', '酉': '金',
  '戌': '土', '亥': '水'
} as const;

// ==================== 工具函数 ====================

/**
 * 获取天干地支的阴阳属性
 */
function 获取天干地支阴阳(天干地支: string): 阴阳 {
  return 阴阳映射表[天干地支] || '';
}

/**
 * 获取天干地支的五行属性
 */
function 获取天干地支五行(天干地支: string): 五行 {
  return 五行映射表[天干地支] || '';
}

/**
 * 从八字对象构建柱信息
 */
function 构建柱(
  八字: EightChar,
  获取天干: (八字: EightChar) => string,
  获取地支: (八字: EightChar) => string,
  获取纳音: (八字: EightChar) => string,
  获取藏干: (八字: EightChar) => string[],
  获取天干十神: (八字: EightChar) => string,
  获取地支十神: (八字: EightChar) => string[],
  获取地势: (八字: EightChar) => string
): 柱 {
  const 天干 = 获取天干(八字);
  const 地支 = 获取地支(八字);
  
  return {
    天干,
    地支,
    纳音: 获取纳音(八字),
    藏干: 获取藏干(八字),
    天干十神: 获取天干十神(八字),
    地支十神: 获取地支十神(八字),
    地势: 获取地势(八字),
    天干阴阳: 获取天干地支阴阳(天干),
    天干五行: 获取天干地支五行(天干),
    地支阴阳: 获取天干地支阴阳(地支),
    地支五行: 获取天干地支五行(地支),
  };
}


/**
 * 创建农历对象
 */
function 创建农历对象(生辰: 生辰): Lunar {
  const { 年, 月, 日, 时 = 12, 分 = 0, 秒 = 0 } = 生辰;
  
  if (生辰.类型 === "公历") {
    return Solar.fromYmdHms(年, 月, 日, 时, 分, 秒).getLunar();
  } else {
    return Lunar.fromYmdHms(年, 月, 日, 时, 分, 秒);
  }
}

/**
 * 生成柱的文本描述（Markdown格式，适合大模型分析）
 */
function 生成柱文本(柱名: string, 柱: 柱): string {
  const 干支 = `${柱.天干}${柱.地支}`;
  return `
### ${柱名}：${干支}

**基本信息：**
- **干支组合**：${干支}
- **纳音**：${柱.纳音}
- **地势**：${柱.地势}

**天干分析：**
- **天干**：${柱.天干}
- **五行属性**：${柱.天干五行}
- **阴阳属性**：${柱.天干阴阳}
- **十神关系**：${柱.天干十神}

**地支分析：**
- **地支**：${柱.地支}
- **五行属性**：${柱.地支五行}
- **阴阳属性**：${柱.地支阴阳}
- **十神关系**：${柱.地支十神.join('、')}
- **藏干**：${柱.藏干.join('、')}`;
}

/**
 * 生成排盘结果文本（优化为Markdown格式，适合大模型分析）
 */
function 生成排盘文本(
  性别: "男" | "女",
  生辰: 生辰,
  八字: EightChar,
  年柱: 柱,
  月柱: 柱,
  日柱: 柱,
  时柱: 柱,
  起运: string,
  大运列表: Array<{
    开始年份: number;
    结束年份: number;
    开始年龄: number;
    结束年龄: number;
    干支: string;
    小运: Array<{ 年份: number; 年龄: number; 干支: string }>;
    旬: string;
    旬空: string;
  }>,
  流年列表: Array<{ 年份: number; 年龄: number; 干支: string; 旬: string; 旬空: string }>,
  获取小运: boolean,
  获取流年: boolean
): string {
  const 生辰文本 = `${生辰.类型} ${生辰.年}年${生辰.月}月${生辰.日}日 ${生辰.时}时${生辰.分 || 0}分`;
  const 八字完整 = `${八字.getYear()} ${八字.getMonth()} ${八字.getDay()} ${八字.getTime()}`;
  const 日主 = `${日柱.天干}${日柱.天干五行}`;
  
  const 文本部分: string[] = [];
  
  // 标题和基本信息
  文本部分.push('# 八字排盘分析报告');
  文本部分.push('');
  文本部分.push('## 基本信息');
  文本部分.push('');
  文本部分.push('| 项目 | 内容 |');
  文本部分.push('|------|------|');
  文本部分.push(`| **性别** | ${性别} |`);
  文本部分.push(`| **生辰** | ${生辰文本} |`);
  文本部分.push(`| **八字** | ${八字完整} |`);
  文本部分.push(`| **日主** | ${日主}日主 |`);
  文本部分.push('');
  
  // 四柱详细分析
  文本部分.push('## 四柱八字详细分析');
  文本部分.push('');
  文本部分.push('### 八字总览');
  文本部分.push('');
  文本部分.push(`**年柱**：${年柱.天干}${年柱.地支} | **月柱**：${月柱.天干}${月柱.地支} | **日柱**：${日柱.天干}${日柱.地支} | **时柱**：${时柱.天干}${时柱.地支}`);
  文本部分.push('');
  文本部分.push('---');
  文本部分.push('');
  
  // 各柱详细分析
  文本部分.push(生成柱文本('年柱', 年柱));
  文本部分.push('');
  文本部分.push(生成柱文本('月柱', 月柱));
  文本部分.push('');
  文本部分.push(生成柱文本('日柱', 日柱));
  文本部分.push('');
  文本部分.push(生成柱文本('时柱', 时柱));
  文本部分.push('');
  
  // 大运信息
  文本部分.push('## 大运分析');
  文本部分.push('');
  文本部分.push(`**起运时间**：${起运}`);
  文本部分.push('');
  文本部分.push('### 大运列表');
  文本部分.push('');
  文本部分.push('| 时间段 | 年龄范围 | 大运干支 | 旬 | 旬空 |');
  文本部分.push('|--------|----------|----------|-----|------|');
  大运列表.forEach(dy => {
    文本部分.push(`| ${dy.开始年份}-${dy.结束年份}年 | ${dy.开始年龄}-${dy.结束年龄}岁 | ${dy.干支} | ${dy.旬} | ${dy.旬空} |`);
  });
  文本部分.push('');
  
  // 小运信息
  if (获取小运 && 大运列表.some(dy => dy.小运.length > 0)) {
    文本部分.push('### 小运详情');
    文本部分.push('');
    大运列表.forEach((dy, index) => {
      if (dy.小运.length > 0) {
        文本部分.push(`#### 大运 ${dy.干支}（${dy.开始年份}-${dy.结束年份}年）的小运：`);
        文本部分.push('');
        文本部分.push('| 年份 | 年龄 | 小运干支 |');
        文本部分.push('|------|------|----------|');
        dy.小运.forEach(xy => {
          文本部分.push(`| ${xy.年份}年 | ${xy.年龄}岁 | ${xy.干支} |`);
        });
        文本部分.push('');
      }
    });
  }
  
  // 流年信息
  if (获取流年 && 流年列表.length > 0) {
    文本部分.push('## 流年分析');
    文本部分.push('');
    文本部分.push('### 流年列表');
    文本部分.push('');
    文本部分.push('| 年份 | 年龄 | 流年干支 | 旬 | 旬空 |');
    文本部分.push('|------|------|----------|-----|------|');
    流年列表.forEach(ln => {
      文本部分.push(`| ${ln.年份}年 | ${ln.年龄}岁 | ${ln.干支} | ${ln.旬} | ${ln.旬空} |`);
    });
    文本部分.push('');
  }
  
  // 关键信息总结
  文本部分.push('## 关键信息总结');
  文本部分.push('');
  文本部分.push('### 五行分布');
  const 五行统计: Record<string, number> = { 木: 0, 火: 0, 土: 0, 金: 0, 水: 0 };
  [年柱, 月柱, 日柱, 时柱].forEach(柱 => {
    if (柱.天干五行) 五行统计[柱.天干五行] = (五行统计[柱.天干五行] || 0) + 1;
    if (柱.地支五行) 五行统计[柱.地支五行] = (五行统计[柱.地支五行] || 0) + 1;
  });
  文本部分.push('');
  文本部分.push('| 五行 | 数量 |');
  文本部分.push('|------|------|');
  Object.entries(五行统计).forEach(([五行, 数量]) => {
    文本部分.push(`| ${五行} | ${数量} |`);
  });
  文本部分.push('');
  
  文本部分.push('### 十神关系');
  文本部分.push('');
  文本部分.push(`- **年柱天干十神**：${年柱.天干十神}`);
  文本部分.push(`- **月柱天干十神**：${月柱.天干十神}`);
  文本部分.push(`- **日柱天干十神**：${日柱.天干十神}（日主）`);
  文本部分.push(`- **时柱天干十神**：${时柱.天干十神}`);
  文本部分.push('');
  
  文本部分.push('---');
  文本部分.push('');
  
  return 文本部分.join('\n');
}

// ==================== 主函数 ====================

/**
 * 八字排盘主函数
 * @param 性别 - 性别：男或女
 * @param 生辰 - 生辰信息
 * @param 获取小运 - 是否获取小运信息，默认true
 * @param 获取流年 - 是否获取流年信息，默认true
 * @param 流派 - 排盘流派：1或2，默认2
 * @returns 排盘结果
 */
export function 排盘(
  性别: "男" | "女",
  生辰: 生辰,
  获取小运: boolean = true,
  获取流年: boolean = true,
  流派: 1 | 2 = 2
) {
  // 创建农历对象
  const lunar = 创建农历对象(生辰);
  if (!lunar) {
    throw new Error("错误的日期");
  }

  // 创建八字对象
  const 八字 = EightChar.fromLunar(lunar);
  if (!八字) {
    throw new Error("无法生成八字");
  }
  
  if (流派) {
    八字.setSect(流派);
  }

  // 构建四柱
  const 年柱 = 构建柱(
    八字,
    (b) => b.getYearGan(),
    (b) => b.getYearZhi(),
    (b) => b.getYearNaYin(),
    (b) => b.getYearHideGan(),
    (b) => b.getYearShiShenGan(),
    (b) => b.getYearShiShenZhi(),
    (b) => b.getYearDiShi()
  );
  
  const 月柱 = 构建柱(
    八字,
    (b) => b.getMonthGan(),
    (b) => b.getMonthZhi(),
    (b) => b.getMonthNaYin(),
    (b) => b.getMonthHideGan(),
    (b) => b.getMonthShiShenGan(),
    (b) => b.getMonthShiShenZhi(),
    (b) => b.getMonthDiShi()
  );
  
  const 日柱 = 构建柱(
    八字,
    (b) => b.getDayGan(),
    (b) => b.getDayZhi(),
    (b) => b.getDayNaYin(),
    (b) => b.getDayHideGan(),
    (b) => b.getDayShiShenGan(),
    (b) => b.getDayShiShenZhi(),
    (b) => b.getDayDiShi()
  );
  
  const 时柱 = 构建柱(
    八字,
    (b) => b.getTimeGan(),
    (b) => b.getTimeZhi(),
    (b) => b.getTimeNaYin(),
    (b) => b.getTimeHideGan(),
    (b) => b.getTimeShiShenGan(),
    (b) => b.getTimeShiShenZhi(),
    (b) => b.getTimeDiShi()
  );

  // 获取大运信息
  const 运 = 八字.getYun(性别 === '女' ? 0 : 1, 八字.getSect());
  const 起运 = `${运.getStartYear()}年${运.getStartMonth()}月${运.getStartDay()}日${运.getStartHour()}时后起运`;
  const 原大运列表 = 运.getDaYun().slice(1);
  
  // 处理大运和流年数据
  const 大运列表: Array<{
    开始年份: number;
    结束年份: number;
    开始年龄: number;
    结束年龄: number;
    干支: string;
    小运: Array<{ 年份: number; 年龄: number; 干支: string }>;
    旬: string;
    旬空: string;
  }> = [];
  
  const 流年列表: Array<{
    年份: number;
    年龄: number;
    干支: string;
    旬: string;
    旬空: string;
  }> = [];
  
  for (const item of 原大运列表) {
    // 获取流年
    if (获取流年) {
      for (const 流年 of item.getLiuNian()) {
        流年列表.push({
          年份: 流年.getYear(),
          年龄: 流年.getAge(),
          干支: 流年.getGanZhi(),
          旬: 流年.getXun(),
          旬空: 流年.getXunKong(),
        });
      }
    }
    
    // 获取大运
    大运列表.push({
      开始年份: item.getStartYear(),
      结束年份: item.getEndYear(),
      开始年龄: item.getStartAge(),
      结束年龄: item.getEndAge(),
      干支: item.getGanZhi(),
      小运: 获取小运 ? item.getXiaoYun().map(xy => ({
        年份: xy.getYear(),
        年龄: xy.getAge(),
        干支: xy.getGanZhi(),
      })) : [],
      旬: item.getXun(),
      旬空: item.getXunKong(),
    });
  }

  // 生成结果文本
  const 文本 = 生成排盘文本(
    性别,
    生辰,
    八字,
    年柱,
    月柱,
    日柱,
    时柱,
    起运,
    大运列表,
    流年列表,
    获取小运,
    获取流年
  );

  return {
    生辰,
    八字: 八字.getYear() + 八字.getMonth() + 八字.getDay() + 八字.getTime(),
    年柱,
    月柱,
    日柱,
    时柱,
    起运,
    大运列表,
    流年列表,
    文本,
  };
}

